//
// Created by HP on 2022/1/22.
//

#ifndef VULKAN_TUTORIAL_LVE_RENDERER_H
#define VULKAN_TUTORIAL_LVE_RENDERER_H

//
// Created by HP on 2022/1/3.
//

#include "lve_device.h"
#include "lve_swap_chain.h"
#include "lve_model.h"

// std
#include <memory>
#include <cassert>
#include <limits>

namespace lve {
    class LveRenderer {
    public:

        LveRenderer(LveWindow& lveWindow, LveDevice& device);
        ~LveRenderer();

        LveRenderer(const LveRenderer&) = delete;
        LveRenderer& operator=(const LveRenderer&) = delete;

        [[nodiscard]] VkRenderPass getSwapChainRenderPass() const { return lveSwapChain->getRenderPass(); }
        [[nodiscard]] float getAspectRatio() const { return lveSwapChain->extentAspectRatio(); }
        [[nodiscard]] bool isFrameInProgress() const { return isFrameStarted; }

        [[nodiscard]] VkCommandBuffer getCurrentCommandBuffer() const {
            assert(isFrameStarted && "Cannot get command buffer when frame not in progress.");
            return commandBuffers[currentFrameIndex];
        }

        [[nodiscard]] uint32_t getFrameIndex() const {
            assert(isFrameStarted && "Cannot get frame index when frame not in progress.");
            return currentFrameIndex;
        }

        VkCommandBuffer beginFrame();
        void endFrame();
        void beginSwapChainRenderPass(VkCommandBuffer commandBuffer);
        void endSwapChainRenderPass(VkCommandBuffer commandBuffer);

    private:
        void createCommandBuffers();
        void freeCommandBuffers();
        void recreateSwapChain();

        LveWindow& lveWindow;
        LveDevice& lveDevice;
        std::unique_ptr<LveSwapChain> lveSwapChain;
        std::vector<VkCommandBuffer> commandBuffers;

        uint32_t currentImageIndex = 0;
        uint32_t currentFrameIndex = 0;
        bool isFrameStarted;
    };
}


#endif //VULKAN_TUTORIAL_LVE_RENDERER_H
